package com.lazy.tcp;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;



public class TelnetClientHandler extends SimpleChannelUpstreamHandler {
    private static Logger logger = Logger.getLogger("TelnetClientHandler");
    static final ChannelGroup channels = new DefaultChannelGroup();
       /** store the data that received */
    private final BlockingQueue<String> answerQueue = new LinkedBlockingQueue<String>();
    
    private static AtomicInteger totalReceived = new AtomicInteger();
    
    public static int getReceivePacketCount() {
        return totalReceived.get();
    }
    
    @Override
    public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
        if (e instanceof ChannelStateEvent) {
            logger.info(e.toString());
        }
        super.handleUpstream(ctx, e);
    }
    
    @Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
        logger.info("channel connected ...");
//      logger.info("local:" + e.getChannel().getLocalAddress().toString());
//      logger.info("remote:" + e.getChannel().getRemoteAddress().toString());
        e.getFuture().addListener(new ConnectedListener());
    }

    @Override
    public void channelDisconnected(
            ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
        logger.info("channel disconnected ...");
        // Unregister the channel from the global channel list
        // so the channel does not receive messages anymore.
        channels.remove(e.getChannel());
    }

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {        
        // Cast to a String first.
        // We know it is a String because we put some codec in TelnetPipelineFactory.
        String request = (String) e.getMessage();
        totalReceived.addAndGet(1);
        // Generate and write a response.
        String response = null;
        logger.info("server received:" + request);
        boolean close = false;
        if ("bye".equals(request.toLowerCase())) {
            response = "bye\r\n";
            close = true;
        }

        // We do not need to write a ChannelBuffer here.
        // We know the encoder inserted at TelnetPipelineFactory will do the conversion.
        ChannelFuture future = e.getChannel().write(response);

        // Close the connection after sending 'Have a good day!'
        // if the client has sent 'bye'.
        if (close) {
            future.addListener(ChannelFutureListener.CLOSE);
        }
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
        logger.warn("Unexpected exception from downstream." + e.getCause());
        e.getChannel().close();
    }
    
    private static final class ConnectedListener implements ChannelFutureListener {
        
        public void operationComplete(ChannelFuture future) throws Exception {
            if (future.isSuccess()) {
                // Register the channel to the global channel list
                // so the channel received the messages from others.
                channels.add(future.getChannel());
            } else {
                future.getChannel().close();
            }
        }
    }
}
